POJ 3276 Face The Right Way(反转问题)

题意:

$N\le 5000个奶牛,有初始朝向B/F$
$现要通过每次反转K个奶牛操作,即B/F状态互换,使得所有奶牛最终都是F状态$
$求出最小反转次数M,以及这个最小M的下的最小K$

分析:

$这类问题都一个苛刻的性质,即当前状态必然确定这个位置是否反转$
$本题考虑枚举K,对于每个K来求M$
$考虑使用f[i]:=记录f[i\sim i-k+1]这个区间是否被反转$
$那么所有能影响i这个位置的f[i]为f[i-k+1\sim i-1]$
$看这个和以及当前B/F状态即可知道i需不需要被反转$
$最后根据n-k+2\sim n以及对应影响的f[i]和即可知道是否合法$
$对于f[i]和,直接用一个变量维护即可$
$时间复杂度为O(n^2)$

代码:

//
//  Created by TaoSama on 2016-07-29
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, a[N];
int f[N];

int calc(int k) {
    memset(f, 0, sizeof f);
    int sum = 0, ret = 0;
    for(int i = 1; i + k - 1 <= n; ++i) {
        if(a[i] + sum & 1) {
            ++ret;
            f[i] = 1;
        }
        sum += f[i];
        if(i - k + 1 >= 1) sum -= f[i - k + 1];
    }
    for(int i = n - k + 2; i <= n; ++i) {
        if(a[i] + sum & 1) return INF;
        if(i - k + 1 >= 1) sum -= f[i - k + 1];
    }
    return ret;
}

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);
    clock_t _ = clock();

    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d", a + i);
    for(int i = 1; i <= n; ++i) {
        char buf[2]; scanf("%s", buf);
        a[i] = *buf == 'B';
    }

    pair<int, int> ans = make_pair(INF, INF); // m k
    for(int i = 1; i <= n; ++i) {
        int o = calc(i);
        ans = min(ans, make_pair(o, i));
    }
    printf("%d %d\n", ans.second, ans.first);

#ifdef LOCAL
    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
    return 0;
}